home *** CD-ROM | disk | FTP | other *** search
- #ifndef lint
- static char *RCS_move_c = "$Id: move.c,v 1.3 91/03/08 15:57:57 jamesp Exp $";
- #endif
-
- /* --------------------
- vmail -- move.c
-
- Routines to delete or move a mail item from current folder.
-
- Copyright (C) J. Zobel, University of Melbourne, October 1987.
- -------------------- */
-
- #include "defs.h"
- #include <errno.h>
-
- static char prevfile[LEN] = "";
-
- extern int errno;
-
- /* --------------------
- Move current item to folder prevfile (get_name = false) or as read from
- terminal (get_name = true).
- -------------------- */
- void
- move_item(get_name)
- bool get_name;
- {
- char *s, str[LEN], str2[LEN];
- folder f, new_folder(), create_folder();
- item m;
- bool redraw; /* true if screen to be refreshed */
- int fdi, fdo, i = FIRST-1, num, N;
-
- /* get name if required */
- if(get_name || *prevfile == '\0') {
- get_string("folder? ", str);
- if(*str == '\0') {
- addstatus("no name given for folder", true);
- return;
- }
- (void)strcpy(prevfile, str);
- } else
- (void)strcpy(str, prevfile);
- /* find first page of named folder */
- (void)sprintf(str2, "refiling to %s ...", str);
- addstatus(str2, false);
- GOTO_NAME(f, str);
- if(f == (folder) NULL) { /* create folder */
- f = create_folder(str);
- if(f == (folder) NULL)
- return;
- } else {
- if(f->name == curflr->name) {
- addstatus("can't move item to current folder", true);
- return;
- }
- if(f->valid) { /* goto last mail item in folder */
- LAST_OF_NAME(f);
- for(i=FIRST, m=f->mail ; m->next != (item) NULL ; i++, m=m->next)
- ;
- }
- }
- /* remember current location of mail */
- m = curmail;
- num = curmail->number;
- s = curflr->name;
- /* delete item from current folder, update current folder & screen */
- redraw = change_item(true);
- if(f->valid) /* update structures of mail items */
- if(i > lines) {
- /* create new folder record */
- f = new_folder(f);
- f->mail = f->last = m;
- m->prev = m->next = (item) NULL;
- N = f->prev->last->number;
- } else {
- /* insert at end of list of mail items */
- m->prev = f->last; m->next = (item) NULL;
- f->last->next = m;
- f->last = m;
- N = m->prev->number;
- }
- else
- N = next_vacant(f);
- /* to avoid race between "send" or other process in background and vmail
- foreground, compute next free slot, dont just use given value
- */
- (void)sprintf(str2, "%s/%s/%d", mail_dir, f->name, N);
- /* loop until unused file name found */
- for(errno=0 ; (fdo = open(str2, O_WRONLY|O_CREAT|O_EXCL, 0644)) < 0
- && errno == EEXIST ; errno=0) {
- N = N + 1;
- (void)sprintf(str2, "%s/%s/%d", mail_dir, f->name, N);
- }
- if(f->valid)
- m->number = N;
- (void)sprintf(str, "%s/%s/%d", mail_dir, s, num);
- fdi = open(str, O_RDONLY);
- while((i = read(fdi, str2, LEN)) > 0) /* copy original to new */
- (void)write(fdo, str2, i);
- (void)close(fdi);
- (void)close(fdo);
- (void)unlink(str); /* remove original */
- if(redraw)
- display_page();
- else {
- add_page_header(str);
- move(y, 0);
- refresh();
- }
- addstatus("refiled", true);
- if(curflr == (folder) NULL) {
- to_normal();
- exit(1);
- }
- }
-
-
- /* --------------------
- Delete count items.
- -------------------- */
- void
- delete_item(count)
- int count;
- {
- bool redraw = false;
- item m;
- char str[LEN];
-
- for( ; count > 0 ; count--) {
- m = curmail->next;
- redraw = change_item(false);
- if(redraw || m != curmail) /* on new page, or last item deleted */
- break;
- }
- if(redraw)
- display_page();
- else {
- add_page_header(str);
- move(y, 0);
- refresh();
- }
- }
-
-
- /* --------------------
- Structure for deleted item.
- -------------------- */
- struct {
- folder flr;
- int number;
- } deleted = {(folder) NULL, 0};
-
-
- /* --------------------
- Either delete (do_move = false) or prepare to move (do_move = true) item.
- Delete item from current folder, update screen, find new current folder
- if current folder has become empty.
- -------------------- */
- bool
- change_item(do_move)
- bool do_move;
- {
- item tmp, m = curmail;
- folder F, p, f = curflr, pval, nval;
- char s1[LEN], s2[LEN];
- bool redraw, doexit = false;
-
- if(curmail->next == (item) NULL && curmail->prev == (item) NULL) {
- /* have last item in page */
- redraw = true;
- pval = curflr->prev; PREV_VALID(pval);
- nval = curflr->next; NEXT_VALID(nval);
- if(pval == (folder) NULL && nval == (folder) NULL) {
- /* no more active pages */
- if(! do_move)
- addstatus("Deleting last active mail item -- bye", true);
- doexit = true;
- } else {
- /* update pages, pagenum */
- for(p=curflr->prev ; p != (folder) NULL && p->name == curflr->name
- ; p=p->prev)
- p->pages -= 1;
- for(p=curflr->next ; p != (folder) NULL && p->name == curflr->name
- ; p=p->next)
- p->pages -= 1, p->pagenum -= 1;
- /* find next active page, drop current page from list */
- if(curflr->prev != (folder) NULL)
- curflr->prev->next = curflr->next;
- else
- folders = curflr->next;
- if(curflr->next != (folder) NULL)
- curflr->next->prev = curflr->prev;
- /*
- * If the previous page is from the same folder,
- * move to last item on that page. Otherwise,
- * move to first page of next folder if it is
- * available, else move to first page of previous
- * folder if it is available.
- */
- if (pval != (folder) NULL && pval->name == curflr->name) {
- curflr = pval;
- curmail = curflr->mail;
- for ( ; curmail->next != (item) NULL; y++)
- curmail = curmail->next;
- }
- else
- {
- curflr = (nval == (folder) NULL) ? pval : nval;
- curmail = curflr->mail;
- }
- }
- } else {
- redraw = false;
- deleteline();
- /* move first item from next to current */
- if(curflr->next != (folder) NULL && curflr->name == curflr->next->name)
- show_title(s1, FIRST+lines-1, curflr->next->mail);
- for(p=curflr->next ; p != (folder) NULL && p->name == curflr->name ;
- p=p->next) {
- tmp = p->mail;
- p->mail = tmp->next;
- if(p->mail == (item) NULL) { /* remove folder from list */
- p->prev->next = p->next;
- if(p->next != (folder) NULL)
- p->next->prev = p->prev;
- /* update page counts */
- for(F=p->prev ; F != (folder) NULL && F->name == p->name
- ; F=F->prev)
- F->pages -= 1;
- } else
- p->mail->prev = (item) NULL;
- p->prev->last->next = tmp;
- tmp->prev = p->prev->last;
- tmp->next = (item) NULL;
- p->prev->last = tmp;
- }
- /* delete item from linked list of items */
- if(m->prev == (item) NULL)
- curflr->mail = m->next;
- else
- m->prev->next = m->next;
- if(m->next == (item) NULL) {
- curflr->last = m->prev;
- curmail = m->prev;
- y--;
- } else {
- m->next->prev = m->prev;
- curmail = m->next;
- }
- move(y, 0);
- }
- if(! do_move) {
- deleted.flr = f;
- deleted.number = m->number;
- (void)sprintf(s1, "%s/%s/%d", mail_dir, f->name, m->number);
- (void)sprintf(s2, "%s/%s/#%d", mail_dir, f->name, m->number);
- (void)rename(s1, s2);
- if(doexit) {
- to_normal();
- exit(0);
- }
- }
- return(redraw);
- }
-
-
- /* --------------------
- Create folder of given name if user agrees, creating directory and
- entry in linked list of folders.
- -------------------- */
- folder
- create_folder(str)
- char *str;
- {
- struct stat statbuf;
- char str2[LEN], c;
- folder fnew, p, f;
-
- squash(str);
- (void)sprintf(str2, "%s does not exist (or is empty) - create? ", str);
- mvaddstr(STATUS, 0, str2); refresh();
- c = getchar();
- move(STATUS, 0); clrtoeol(); move(y, 0); refresh();
- if(c != 'y')
- return((folder) NULL);
- for(p=(folder) NULL, f=folders ; f != (folder) NULL &&
- strcmp(str, f->name) > 0 ; p=f, f=f->next)
- ;
- /* create physical folder */
- (void)sprintf(str2, "%s/%s", mail_dir, str);
- if(stat(str2, &statbuf)) { /* doesn't exist */
- if(mkdir(str2, folder_protect)) {
- addstatus("Cannot make folder", true);
- return((folder) NULL);
- }
- } else
- if(!(statbuf.st_mode & S_IREAD) || !(statbuf.st_mode & S_IWRITE)
- || !(statbuf.st_mode & S_IEXEC)) {
- addstatus("Cannot write in folder", true);
- return((folder) NULL);
- }
- /* make a new folder record, insert it */
- fnew = NEW(mail_folder);
- fnew->name = NEWSTR(strlen(str)+1);
- (void)strcpy(fnew->name, str);
- fnew->mail = fnew->last = (item) NULL;
- fnew->next = fnew->prev = (folder) NULL;
- fnew->pages = fnew->pagenum = 1;
- fnew->valid = false;
- if(p == (folder) NULL) {
- fnew->next = folders;
- folders->prev = fnew;
- folders = fnew;
- } else {
- p->next = fnew;
- if(f != (folder) NULL)
- f->prev = fnew;
- fnew->prev = p;
- fnew->next = f;
- }
- return(fnew);
- }
-
-
- /* --------------------
- Crude undo. Sophisticated undo rather too painful to code.
- -------------------- */
- void
- undo()
- {
- folder f = deleted.flr, p;
- char s1[LEN], s2[LEN];
-
- if(f == (folder) NULL) {
- addstatus("nothing to undo", true);
- return;
- } else {
- addstatus("undoing ...", true);
- deleted.flr = (folder) NULL;
- }
- (void)sprintf(s1, "%s/%s/#%d", mail_dir, f->name, deleted.number);
- (void)sprintf(s2, "%s/%s/%d", mail_dir, f->name, deleted.number);
- (void)rename(s1, s2);
- /* find first page of folder */
- p = f; FRST_OF_NAME(p);
- /* find last page of folder */
- LAST_OF_NAME(f);
- curflr = p;
- p->next = f->next;
- /* should free old folder/mail records */
- /* p->valid = false; */
- p->mail = p->last = (item) NULL;
- p->pagenum = p->pages = 1;
- if(p->next != (folder) NULL)
- p->next->prev = p;
- (void)find_mail(curflr, false);
- curmail = curflr->mail;
- y = FIRST;
- display_page();
- }
-
-
- /* --------------------
- Pack current folder. Unsets "deleted" if last removed record was
- on current folder.
- -------------------- */
- void
- pack_folder()
- {
- folder f = curflr;
- item m;
- char path[LEN], s1[LEN], s2[LEN];
- bool found;
- int newnum = 1;
-
- addstatus("Packing folder ...", false);
- FRST_OF_NAME(f);
- /* unset undo if packing that folder */
- if(deleted.flr != (folder) NULL && deleted.flr->name == curflr->name)
- deleted.flr = (folder) NULL;
- (void)sprintf(path, "%s/%s/", mail_dir, curflr->name);
- for( ; f != (folder) NULL && f->name == curflr->name ; f=f->next)
- for(m=f->mail ; m != (item) NULL ; m=m->next) {
- for(found=false ; !found && newnum < m->number ; ) {
- (void)sprintf(s1, "%s%d", path, newnum);
- if(! access(s1, R_OK))
- newnum++;
- else
- found = true;
- }
- if(found) {
- (void)sprintf(s2, "%s%d", path, m->number);
- (void)rename(s2, s1);
- m->number = newnum;
- }
- }
- display_page();
- }
-